package com.cskaoyan.javase.oop2._1extends._7initialization._1basic;

/**
 * 我们通过一个引例，练习来讲解这个问题：
 * 创建一个Person类，有name属性和eat方法
 * 创建一个Star类，有stageName属性和sing方法
 * Star类要继承Person类
 * 创建Star类对象，画出这个过程的内存图，描述子类对象初始化的过程。
 *
 * 结论:
 *      1.触发子类类加载,会优先类加载父类,这也是一个类加载的时机.
 *      --> 一旦想要初始化子类,会优先初始化父类
 *      而如果存在多层继承层次
 *      那么类加载就会从顶层父类开始,向下进行
 *      "先父后子"
 *
 *      2.new子类对象,只会创建一个子类对象,并不会创建父类对象
 *
 *      3.接下来子类对象中会专门开辟一片独立的区域
 *          用来存储父类的成员变量
 *          而子类自身的成员变量仍会存储在自身对象当中
 *          这样子类对象就被划分为了两个区域:
 *              a.独属于父类成员的区域,用super指向
 *              b.子类自身成员的区域,用this指向整个子类对象
 *
 *      4.(重点)父子类的成员各自存储在各自的区域,那么它们的赋值是如何进行的呢?
 *          赋值的顺序是什么样的?
 *          赋值的结果是什么样的?
 *          首先,给成员变量的赋值手段中,排除默认初始化,默认值永远最先进行,无论父子类的成员变量
 *          通过验证
 *          我们发现: 父子类成员变量的赋值顺序,是"先父后子"的
 *              先给父类的成员变量赋值,然后再给子类成员变量赋值
 *
 *       5.(最重要)为什么?为什么父子类成员变量的赋值顺序,是"先父后子"的呢?
 *              这肯定是一个语法设计,那么它又是如何实现的呢?
 *              在一个类当中,给成员变量赋值的手段有:
 *                  a.默认初始化
 *                  b.显式赋值
 *                  c.构造代码块赋值
 *                  d.构造器赋值
 *              在一个类中,最后进行的是构造器赋值
 *              现在有了继承,存在父子类,两个类,那么要想保证父类成员变量先于子类完成赋值,怎么办呢?
 *              只需要保证父类的最后一个赋值手段  先于子类的第一个赋值手段执行即可
 *              具体来说,就是保证构造器的执行"先父后子",就可以保证父子类成员变量赋值顺序的"先父后子"
 *              实际上Java就是采取这种设计
 *              这里讲解子类对象初始化的两种形式:
 *              a.隐式的子类对象初始化:
 *                  在任何类的,任何构造器中,如果该构造器的第一行
 *                  没有直接,明确的使用this或者super表示调用自身构造器或者父类构造器
 *                  那么第一行就隐含了一条语句:
 *                  super(); 表示调用父类无参构造器
 *              super在子类构造器中,可以表示调用父类构造器,语法:super(实参列表)
 *
 *              隐式的子类对象初始化无法传参,无法完成父类成员变量的赋值
 *              于是就有了显式的子类对象初始化:
 *                  在子类构造器的第一行,明确去调用父类的构造器
 *                  语法: super(实参);
 *      总之,无论是子类对象的隐式初始化,还是显式初始化
 *      都是为了保证父类构造器先于子类构造器代码执行
 *      最终保证父子类成员变量赋值顺序的"先父后子"
 *
 * @since 09:39
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        // Star s = new Star();
        // System.out.println(s.stageName);
        Star s = new Star("马云");
        System.out.println(s.name);

        Star s2 = new Star("萧炎", "肖宣");
        System.out.println(s2.name);
        System.out.println(s2.stageName);
    }
}

class Person {
    /*static {
        System.out.println("Person类初始化~");
    }*/
    String name = "张三";
    /*{
        System.out.println("Person构造器执行~");
    }*/

    public Person() {
        // 隐含super(); 指向父类Object类的无参构造器
    }

    public Person(String name) {
        this.name = name;
    }

    public void eat() {
        System.out.println("是人就要吃饭~");
    }
}

class Star extends Person {
    /*static {
        System.out.println("Star类初始化~");
    }*/
    String stageName = "法外狂徒-" + name;
    /*{
        System.out.println("Star构造器执行~");
    }*/

    public Star() {
        // 隐含super();表示调用父类无参构造器
    }

    public Star(String name) {
        // 显式的子类对象初始化
        super(name);
    }

    public Star(String name, String stageName) {
        // 显式的子类对象初始化
        super(name);
        this.stageName = stageName;
    }

    public void sing() {
        System.out.println("爱的供养~");
    }
}